{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 0 prepare data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using TensorFlow backend.\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import pandas as pd\n",
    "import tensorflow as tf\n",
    "%matplotlib inline\n",
    "f='epochs/epoch01_front.mkv'\n",
    "import  skimage \n",
    "from skimage.transform import resize\n",
    "import keras"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 0  video process"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import imageio\n",
    "try :\n",
    "    reader = imageio.get_reader(f)\n",
    "    plt.imshow(reader.get_data(30))\n",
    "    t0_frame,t1_frame,t2_frame,t3_frame=reader.get_data(0),reader.get_data(1),reader.get_data(2),reader.get_data(3)\n",
    "    t0_frame=np.array(t0_frame)\n",
    "    t1_frame=np.array(t1_frame)\n",
    "    t2_frame=np.array(t2_frame)\n",
    "    t3_frame=np.array(t3_frame)\n",
    "except :\n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "## Preprocess\n",
    "def img_pre_process(img):\n",
    "    \"\"\"\n",
    "    Processes the image and returns it\n",
    "    :param img: The image to be processed\n",
    "    :return: Returns the processed image\n",
    "    \"\"\"\n",
    "    ## Chop off 1/3 from the top and cut bottom 150px(which contains the head of car)\n",
    "    shape = img.shape\n",
    "    img = img[int(shape[0]/3):shape[0]-150, 0:shape[1]]\n",
    "    img=img/255.\n",
    "    print(img.shape)\n",
    "    \n",
    "    ## Resize the image\n",
    "    resize_img=resize(img, (128, 384), mode='reflect')\n",
    "    ## Return the image sized as a 4D array\n",
    "    return resize_img#np.resize(img, (w, h, c))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 0 .make one frame data for debug"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "t0_frame=np.load('src/t0_frame.npy')\n",
    "t1_frame=np.load('src/t1_frame.npy')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false,
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x7f1d3d89ea20>"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\nC66PopQeAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f1d40c21710>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.imshow(t0_frame)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# for tf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "test_frame0=np.load('src/test_frame0.npy')\n",
    "test_frame1=np.load('src/test_frame1.npy')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1.buid model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from keras.layers import Dense,Deconv2D,Conv2D,BatchNormalization,Activation,Concatenate,Reshape,Conv1D,Permute\n",
    "from keras.engine.topology import Layer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "sess = tf.Session()\n",
    "\n",
    "from keras import backend as K\n",
    "K.set_session(sess)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.1 place holdholer \n",
    "- a pair of input frame ** I_t ,I_t+1 **\n",
    "- learning_rate\n",
    "- steering"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def model_input(img_h,img_w,img_c):\n",
    "    I_t0=tf.placeholder(tf.float32,(None,img_h,img_w,img_c),name='frame_t0')\n",
    "    I_t1=tf.placeholder(tf.float32,(None,img_h,img_w,img_c),name='frame_t1')\n",
    "    learning_rate=tf.placeholder(tf.float32)\n",
    "    steering=tf.placeholder(tf.float32,(None,1),name='steering')\n",
    "    \n",
    "    return I_t0,I_t1,learning_rate,steering"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.2 place holder shape test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "img_h,img_w,img_c=128,384,3\n",
    "I_t0,I_t1,learning_rate,steering=model_input(img_h,img_w,img_c)\n",
    "assert I_t0.shape.as_list()==[None,128,384,3]\n",
    "assert I_t1.shape.as_list()==[None,128,384,3]\n",
    "assert steering.shape.as_list()==[None,1]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##  1.3 basic structure of conv ,dconv"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](src/net2.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](src/w1.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](src/net.png)\n",
    "![](src/w2.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def conv(h_0,filters,kernel_size,strides):\n",
    "        kernel_initializer=keras.initializers.TruncatedNormal(mean=0.0,stddev=0.0001)\n",
    "    \n",
    "        h1=Conv2D(filters=filters,kernel_size=kernel_size,strides=strides,padding='same',kernel_initializer=kernel_initializer)(h_0)\n",
    "        h1_bn=BatchNormalization()(h1,training=True)\n",
    "        h1_o=Activation('relu')(h1_bn)\n",
    "        return h1_o\n",
    "def deconv(h_0,filters,kernel_size,strides):\n",
    "        kernel_initializer=keras.initializers.TruncatedNormal(mean=0.0,stddev=0.0001)\n",
    "    \n",
    "        h1=Deconv2D(filters=filters,kernel_size=kernel_size,strides=strides,padding='same',kernel_initializer=kernel_initializer)(h_0)\n",
    "        h1_bn=BatchNormalization()(h1,training=True)\n",
    "        h1_o=Activation('relu')(h1_bn)\n",
    "        return h1_o\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def conv_deconv_net(frame):\n",
    "\n",
    "    ###to deconv\n",
    "    h10_o=conv(frame,filters=32,kernel_size=3,strides=1)\n",
    "\n",
    "    h11_o=conv(h10_o,filters=64,kernel_size=3,strides=2)\n",
    "    ###to deconv\n",
    "    h20_o=conv(h11_o,filters=64,kernel_size=3,strides=1)\n",
    "\n",
    "    h21_o=conv(h20_o,filters=128,kernel_size=3,strides=2)\n",
    "\n",
    "    ###to deconv\n",
    "    h30_o=conv(h21_o,filters=128,kernel_size=3,strides=1)\n",
    "\n",
    "    h31_o=conv(h30_o,filters=256,kernel_size=3,strides=2)\n",
    "    ###to deconv\n",
    "    h40_o=conv(h31_o,filters=256,kernel_size=3,strides=1)\n",
    "\n",
    "    h41_o=conv(h40_o,filters=512,kernel_size=3,strides=2)\n",
    "    ###to deconv\n",
    "    h50_o=conv(h41_o,filters=512,kernel_size=3,strides=1)\n",
    "\n",
    "    h51_o=conv(h50_o,filters=1024,kernel_size=3,strides=2)\n",
    "    #embeding layer\n",
    "    embeding=conv(h51_o,filters=1024,kernel_size=3,strides=1)\n",
    "\n",
    "\n",
    "    #deconv\n",
    "    d5=deconv(embeding,filters=512,kernel_size=3,strides=2)\n",
    "    d4_i=Concatenate(axis=-1)([d5,h50_o])\n",
    "\n",
    "    d4=deconv(d4_i,filters=256,kernel_size=3,strides=2)\n",
    "\n",
    "    d3_i=Concatenate(axis=-1)([d4,h40_o])\n",
    "\n",
    "    d3=deconv(d3_i,filters=128,kernel_size=3,strides=2)\n",
    "\n",
    "\n",
    "\n",
    "    d2_i=Concatenate(axis=-1)([d3,h30_o])\n",
    "\n",
    "    d2=deconv(d2_i,filters=64,kernel_size=3,strides=2)\n",
    "\n",
    "\n",
    "    d1_i=Concatenate(axis=-1)([d2,h20_o])\n",
    "\n",
    "    out=deconv(d1_i,filters=32,kernel_size=3,strides=2)\n",
    "\n",
    "\n",
    "    return out,embeding"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  2 depth_net"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def clip_relu(x):\n",
    "\n",
    "    x=tf.clip_by_value(x, 1, 100)\n",
    "    \n",
    "    return x\n",
    "def depth_net(frame):\n",
    "\n",
    "    top,_=conv_deconv_net(frame)\n",
    "    top=Conv2D(filters=1,kernel_size=1,strides=1,padding='same',kernel_initializer=keras.initializers.glorot_normal())(top)\n",
    "    depth=Activation(clip_relu)(top)\n",
    "\n",
    "    return depth\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  2.2 depth to point cloud\n",
    "linear transformation without trainabel weight\n",
    "\n",
    "you shulud input camera intrinsics (cx,cy,f) to define this layer\n",
    "\n",
    "if intrinsics is unavalibel ,use [0.5,0.5,1.0] as default\n",
    "\n",
    "![](src/param4.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Cloud_transformer():\n",
    "    def __init__(self,intrinsics=[0.5,0.5,1.0], **kwargs):\n",
    "        self.output_dim = 3\n",
    "        self.cam_intrinsics = intrinsics\n",
    "        self.build()\n",
    "\n",
    "    def build(self):\n",
    "        self.cx_=self.cam_intrinsics[0]\n",
    "        \n",
    "        self.cy_=self.cam_intrinsics[1]\n",
    "        \n",
    "        self.cf_=self.cam_intrinsics[2]\n",
    "        \n",
    "        self.cx=tf.constant(self.cam_intrinsics[0],dtype=tf.float32)\n",
    "        \n",
    "        self.cy=tf.constant(self.cam_intrinsics[1],dtype=tf.float32)\n",
    "        \n",
    "        self.cf=tf.constant(self.cam_intrinsics[2],dtype=tf.float32)\n",
    "        \n",
    "    def mesh_grid(self,width,height):\n",
    "        # get \n",
    "        \"\"\"\n",
    "        [(xi/w-cx)/f,(yi/h-cy)/f,1]\n",
    "        \n",
    "        next just \n",
    "        \n",
    "        d*[(xi/w-cx)/f,(yi/h-cy)/f,1]\n",
    "         to get [Xi,Yi,Zi]\n",
    "        \n",
    "        \"\"\"\n",
    "      \n",
    "        x_linspace=tf.linspace(-self.cx_,1-self.cx_,width)\n",
    "        y_linspace=tf.linspace(-self.cy_,1-self.cy_,height)\n",
    "        \n",
    "#         x_cord,y_cord=tf.meshgrid(x_linspace,y_linspace)\n",
    "        y_cord,x_cord=tf.meshgrid(y_linspace,x_linspace)\n",
    "        \n",
    "        \n",
    "        x_cord=tf.reshape(x_cord,[-1])\n",
    "        y_cord=tf.reshape(y_cord,[-1])\n",
    "        \n",
    "        f_=tf.ones_like(x_cord)\n",
    "        \n",
    "        x_=tf.div(x_cord,self.cf)\n",
    "        y_=tf.div(y_cord,self.cf)\n",
    "        \n",
    "        grid=tf.concat([x_,y_,f_],0)\n",
    "        return grid\n",
    "        \n",
    "    def transform(self,x):\n",
    "        \n",
    "        #get input shape\n",
    "        batch_size=tf.shape(x)[0]\n",
    "        width=tf.shape(x)[1]\n",
    "        height=tf.shape(x)[2]\n",
    "        channel=tf.shape(x)[3]\n",
    "        batch_size=tf.cast(batch_size,tf.int32)\n",
    "        width=tf.cast(width,tf.int32)\n",
    "        height=tf.cast(height,tf.int32)\n",
    "        channel=tf.cast(channel,tf.int32)\n",
    "        \n",
    "        \n",
    "        #grid\n",
    "        grid=self.mesh_grid(width,height)\n",
    "        grid=tf.expand_dims(grid,0)\n",
    "        grid=tf.reshape(grid,[-1])\n",
    "        \n",
    "        \n",
    "        grid_stack = tf.tile(grid, tf.stack([batch_size]))\n",
    "        grid_stack=tf.reshape(grid_stack,[batch_size,3,-1])\n",
    "        depth=tf.reshape(x,[batch_size,1,-1])\n",
    "        depth=tf.concat([depth]*self.output_dim,1)\n",
    "        \n",
    "        point_cloud=tf.multiply(depth,grid_stack)\n",
    "#         pc3=tf.reshape(pc3,[batch_size,width,height,self.output_dim])\n",
    "        \n",
    "        return point_cloud\n",
    "\n",
    "    def __call__(self, x):\n",
    "        point_cloud=self.transform(x)\n",
    "        return point_cloud\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def structure_net(input_frame,reuse=False):\n",
    "    with tf.variable_scope('structure_net',reuse=reuse):\n",
    "        depth_output=depth_net(input_frame)\n",
    "        point_cloud_output=Cloud_transformer()(depth_output)\n",
    "        return point_cloud_output,depth_output\n",
    "        \n",
    "        \n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##  3. motion net\n",
    "#### 3.1 param_net\n",
    "get 3D rigid motions parameter\n",
    "\n",
    "- p [px,py,pz]   rotation pivot points :use a sigmoid activation to predict a weight avarage in a 20m*30m grid  \n",
    "- t [tx,ty,tz]    linear movement translation \n",
    "- r [sin(a),sin(b),sin(y)]  Euler angle representation  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "![](src/param1.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def sin_relu(x):\n",
    "    x=tf.clip_by_value(x, -1., 1.)\n",
    "    \n",
    "    return x\n",
    "\n",
    "def param_net(frame_t0,frame_t1,k_obj=4,):\n",
    "    init=keras.initializers.TruncatedNormal(mean=0.0,stddev=0.0001)\n",
    "    frame_pair=tf.concat([frame_t0,frame_t1],-1)\n",
    "    top,embed=conv_deconv_net(frame_pair)\n",
    "    mask=Conv2D(filters=k_obj,kernel_size=1,strides=1,padding='same',kernel_initializer=init)(top)\n",
    "    \n",
    "    \n",
    "    embed=Dense(512,kernel_initializer=init)(embed)\n",
    "    embed=Dense(512,kernel_initializer=init)(embed)\n",
    "    embed=Reshape([-1])(embed)\n",
    "    \n",
    "    \n",
    "    cam_t_=Dense(3,kernel_initializer=init)(embed)\n",
    "    cam_t=Activation('relu')(cam_t_)\n",
    "    cam_p=Dense(600,kernel_initializer=init)(embed)\n",
    "    \n",
    "    cam_p=Activation('relu')(cam_p)\n",
    "    cam_r=Dense(3,kernel_initializer=init)(embed)\n",
    "    \n",
    "    cam_r=Activation(sin_relu)(cam_r)\n",
    "    \n",
    "    \n",
    "    \n",
    "    obj_mask= Activation('sigmoid')(mask) \n",
    "    obj_t=Activation('relu')(Dense(3*k_obj,kernel_initializer=init)(embed))\n",
    "    obj_t=tf.reshape(obj_t,(-1,k_obj,3))\n",
    "    obj_p=Activation('relu')(Dense(600*k_obj,kernel_initializer=init)(embed))\n",
    "    obj_p=tf.reshape(obj_p,(-1,k_obj,600))\n",
    "    \n",
    "    obj_r=Activation(sin_relu)(Dense(3*k_obj,kernel_initializer=init)(embed))\n",
    "    obj_r=tf.reshape(obj_r,(-1,k_obj,3))\n",
    "    \n",
    "    return [cam_t,cam_p,cam_r],[obj_t,obj_p, obj_r,obj_mask]\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " # 3.2 get Optical_flow anf motion field"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](src/param2.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "class Optical_transformer():\n",
    "\n",
    "    def __init__(self,intrinsics=[0.5,0.5,1.0],img_shape=[384,128], **kwargs):\n",
    "        \n",
    "        self.cam_intrinsics = intrinsics\n",
    "        self.img_w=self.np_tf(img_shape[0])\n",
    "        self.img_h=self.np_tf(img_shape[1])\n",
    "        self.img_w_=float(img_shape[0])\n",
    "        self.img_h_=float(img_shape[1])\n",
    "        \n",
    "        \n",
    "        \n",
    "        self.cx_=self.cam_intrinsics[0]\n",
    "        \n",
    "        self.cy_=self.cam_intrinsics[1]\n",
    "        \n",
    "        self.cf_=self.cam_intrinsics[2]\n",
    "        \n",
    "        \n",
    "        \n",
    "        self.cx=self.np_tf(self.cam_intrinsics[0])\n",
    "        \n",
    "        self.cy=self.np_tf(self.cam_intrinsics[1])\n",
    "        \n",
    "        self.cf=self.np_tf(self.cam_intrinsics[2])\n",
    "        \n",
    "\n",
    "        so3_a=np.array([\n",
    "            [0,-1,0,1,0,0,0,0,0],\n",
    "            [1,0,0,0,1,0,0,0,0],\n",
    "            [0,0,0,0,0,0,0,0,1]\n",
    "        ])\n",
    "\n",
    "        so3_b=np.array([\n",
    "            [0,0,1,0,0,0,-1,0,0],\n",
    "            [1,0,0,0,0,0,0,0,1],\n",
    "            [0,0,0,0,1,0,0,0,0]\n",
    "        ])\n",
    "\n",
    "        so3_y=np.array([\n",
    "            [0,0,0,0,0,-1,0,1,0],\n",
    "            [0,0,0,0,1,0,0,0,1],\n",
    "            [1,0,0,0,0,0,0,0,0]\n",
    "        ])\n",
    "\n",
    "#         so3_param=np.concatenate([so3_a,so3_b,so3_y],0)\n",
    "        self.so3_a=self.np_tf(so3_a)\n",
    "        self.so3_b=self.np_tf(so3_b)\n",
    "        self.so3_y=self.np_tf(so3_y)\n",
    "        \n",
    "  \n",
    "    def np_tf(self,array):\n",
    "        return tf.constant(array,tf.float32)\n",
    "    \n",
    "\n",
    "    def build(self,cam_motion,obj_motion,x):\n",
    "                \n",
    "        self.cam_motion=cam_motion\n",
    "        \n",
    "        self.obj_motion=obj_motion\n",
    "        self.mask_size=obj_motion[0].shape.as_list()[1]\n",
    "        self.x_shape=x.shape.as_list()\n",
    "        \n",
    "    \n",
    "#    tranformation     \n",
    "    def so3_mat(self,sin):\n",
    "        #input :sin a,sin b,sin y \n",
    "        #return : SO3\n",
    "        sin=tf.expand_dims(sin,-1)\n",
    "        cos=tf.sqrt(tf.ones_like(sin)-tf.square(sin))\n",
    "        t=tf.concat([sin,cos,tf.ones_like(sin)],-1)\n",
    "        t_a=tf.slice(t,[0,0,0],[-1,1,-1])\n",
    "        t_b=tf.slice(t,[0,1,0],[-1,1,-1])\n",
    "        t_y=tf.slice(t,[0,2,0],[-1,1,-1])\n",
    "        t_a=tf.reshape(t_a,(-1,3))\n",
    "        t_b=tf.reshape(t_b,(-1,3))\n",
    "        t_y=tf.reshape(t_y,(-1,3))\n",
    "        \n",
    "        soa=tf.matmul(t_a,self.so3_a)\n",
    "        soa=tf.reshape(soa,(-1,3,3))\n",
    "        \n",
    "        sob=tf.matmul(t_b,self.so3_b)\n",
    "        sob=tf.reshape(sob,(-1,3,3))\n",
    "        soy=tf.matmul(t_y,self.so3_y)\n",
    "        soy=tf.reshape(soy,(-1,3,3))\n",
    "   \n",
    "        so3=tf.matmul(soa,  tf.matmul(sob,soy))\n",
    "        return so3\n",
    "    def pior_pont(self,p):\n",
    "        batch_size=p.shape.as_list()[0]\n",
    "        p_ret=tf.reshape(p,(-1,30,20))\n",
    "        p_y=tf.reduce_sum(p_ret,1)\n",
    "        p_x=tf.reduce_sum(p_ret,2)\n",
    "        x_loc=tf.linspace(-30.0,30.0,30)\n",
    "        y_loc=tf.linspace(-20.,20.,20)\n",
    "        P_x_loc=tf.reduce_mean(tf.multiply(p_x,x_loc))\n",
    "        P_x_loc=tf.reshape(P_x_loc,(-1,1))\n",
    "        P_y_loc=tf.reduce_mean(tf.multiply(p_y,y_loc))\n",
    "        P_y_loc=tf.reshape(P_y_loc,(-1,1))\n",
    "        \n",
    "        ground=tf.ones_like(P_y_loc)\n",
    "        P=tf.concat([P_x_loc,P_y_loc,ground],1)\n",
    "        \n",
    "        \n",
    "        return P\n",
    "    \n",
    "    def rigid_motion(self,x,R,p,t):\n",
    "        p=tf.expand_dims(p,-1)\n",
    "        \n",
    "        t=tf.expand_dims(t,-1)\n",
    "        \n",
    "        motion=tf.add(tf.matmul(R,tf.subtract(x,p)),t)\n",
    "\n",
    "        return motion\n",
    "          \n",
    "    \n",
    "    def cam_motion_transform(self,x):\n",
    "        t,p,sin=self.cam_motion\n",
    "        p=self.pior_pont(p)\n",
    "        R=self.so3_mat(sin)\n",
    "        X=self.rigid_motion(x,R,p,t)\n",
    "        \n",
    "        \n",
    "        return X\n",
    "        \n",
    "  \n",
    "    def obj_motion_transform(self,x_input):\n",
    "        t,p,sin,mask=self.obj_motion\n",
    "        p=self.pior_pont(p)\n",
    "        sin=tf.reshape(sin,(-1,3))\n",
    "        p=tf.reshape(p,(-1,3))\n",
    "        t=tf.reshape(t,(-1,3))\n",
    "        x_in=tf.expand_dims(x_input,1)\n",
    "        x_exp=tf.concat([x_in]*self.mask_size,1)\n",
    "        x_=tf.reshape(x_exp,(-1,3,384*128))\n",
    "        \n",
    "        \n",
    "        R=self.so3_mat(sin)\n",
    "        \n",
    "        x=self.rigid_motion(x_,R,p,t)\n",
    "        \n",
    "        \n",
    "        \n",
    "        x=tf.reshape(x,(-1,self.mask_size,3,384*128))\n",
    "        x,motion_map=self.mask_motion(x,mask,x_exp)\n",
    "        X=tf.add(x_input,x)\n",
    "        \n",
    "        \n",
    "        return X,motion_map\n",
    "    \n",
    "    def mask_motion(self,x,mask,x_exp):\n",
    "        mask=tf.reshape(mask,(-1,self.mask_size,1,384*128))\n",
    "        x=tf.subtract(x,x_exp)\n",
    "        motion_map=tf.multiply(x,mask)\n",
    "#         x=tf.reshape(x,(-1,self.mask_size,3,384*128))\n",
    "        x=tf.reduce_sum(motion_map,1)\n",
    "#         print(x.shape.as_list())\n",
    "        \n",
    "        return x,motion_map\n",
    "        \n",
    "        \n",
    "    def tranform_2d(self,x):\n",
    "        x_3d=tf.slice(x,(0,0,0),(-1,1,49152))\n",
    "        y_3d=tf.slice(x,(0,1,0),(-1,1,49152))\n",
    "        z_3d=tf.slice(x,(0,2,0),(-1,1,49152))\n",
    "        x_z=tf.div(x_3d,z_3d)\n",
    "        y_z=tf.div(y_3d,z_3d)\n",
    "        \n",
    "#         x_2d=tf.multiply(self.img_w,tf.add(tf.multiply(self.cf,x_z),self.cx))\n",
    "#         y_2d=tf.multiply(self.img_h,tf.add(tf.multiply(self.cf,y_z),self.cy))\n",
    "        x_2d=tf.add(tf.multiply(self.cf,x_z),self.cx)\n",
    "        y_2d=tf.add(tf.multiply(self.cf,y_z),self.cy)\n",
    "        pos_2d_new=tf.concat([x_2d,y_2d],1)\n",
    "        return pos_2d_new\n",
    "\n",
    "    def get_flow(self,pos_2d_new):\n",
    "        \n",
    "        \n",
    "        x_linspace = tf.linspace(0.,1.,int(self.img_w_))\n",
    "        y_linspace = tf.linspace(0.,1.,int(self.img_h_))\n",
    "        y_linspace,x_linspace = tf.meshgrid( y_linspace,x_linspace)\n",
    "        x_linspace = tf.reshape(x_linspace, [1,-1])\n",
    "        y_linspace = tf.reshape(y_linspace, [1,-1])\n",
    "        pos_ori=tf.concat([x_linspace,y_linspace],0)\n",
    "        flow=tf.subtract(pos_2d_new,pos_ori)\n",
    "        \n",
    "        \n",
    "        return flow\n",
    "\n",
    "  \n",
    "    def __call__(self,x,cam_motion,obj_motion,):\n",
    "        self.build( cam_motion,obj_motion,x)\n",
    "\n",
    "        \n",
    "        point_cloud,motion_map=self.obj_motion_transform(x)\n",
    "        \n",
    "        \n",
    "        point_cloud=self.cam_motion_transform(point_cloud)\n",
    "        pix_pos=self.tranform_2d(point_cloud)\n",
    "        flow=self.get_flow(pix_pos)\n",
    "        motion_map=tf.reshape(motion_map,(-1,img_h,img_w,1))\n",
    "        return pix_pos,flow,point_cloud,motion_map\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def motion_net(input_frame_0,input_frame_1,point_cloud_0,reuse=False):\n",
    "    with tf.variable_scope('motion_net',reuse=reuse):\n",
    "        cam_motion,obj_motion=param_net(input_frame_0,input_frame_1,k_obj=4,)\n",
    "        pix_pos,flow,point_cloud,motion_map=Optical_transformer()(point_cloud_0,cam_motion,obj_motion,)\n",
    "        return pix_pos,flow,point_cloud,motion_map\n",
    "        "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " #  3.3 build loss function\n",
    " \n",
    "base on optical flow , use bilieaner interpolate ,to sample the pixel in T_t+1 \n",
    "\n",
    "compute the color  loss"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](src/loss1.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "class get_frame_loss():\n",
    "    def __init__(self):\n",
    "        self.output_size=[128,384]\n",
    "    def __call__(self,frame0,frame1,pos_2d_new,reuse=False):\n",
    "        with tf.variable_scope('frame_loss',reuse=reuse):\n",
    "            batch_size = tf.shape(frame1)[0]\n",
    "            height = 128\n",
    "            width = 384\n",
    "            num_channels = 3\n",
    "            output_height=128\n",
    "            output_width=384\n",
    "\n",
    "\n",
    "\n",
    "            x_s = tf.slice(pos_2d_new, [0, 0, 0], [-1, 1, -1])\n",
    "            y_s = tf.slice(pos_2d_new, [0, 1, 0], [-1, 1, -1])\n",
    "            x_s_flatten = tf.reshape(x_s, [-1])\n",
    "            y_s_flatten = tf.reshape(y_s, [-1])\n",
    "\n",
    "            transformed_image = self._interpolate(frame1,\n",
    "                                                    x_s_flatten,\n",
    "                                                    y_s_flatten,\n",
    "                                                    self.output_size)\n",
    "\n",
    "            transformed_image = tf.reshape(transformed_image, shape=(-1,\n",
    "                                                                    output_height,\n",
    "                                                                    output_width,\n",
    "                                                                     num_channels))\n",
    "\n",
    "            loss=self.compute_loss( frame0,transformed_image )\n",
    "            ####test--------------------------------------------\n",
    "            return loss\n",
    "    \n",
    "    \n",
    "    def compute_loss(self,frame0,transformed_image):\n",
    "        loss=tf.reduce_mean(tf.abs(tf.subtract( frame0,transformed_image)))\n",
    "        return loss\n",
    "        \n",
    "        \n",
    "        \n",
    "        \n",
    "    def _interpolate(self, image, x, y, output_size):\n",
    "        batch_size = tf.shape(image)[0]\n",
    "        height = 128\n",
    "        width = 384\n",
    "        num_channels = tf.shape(image)[3]\n",
    "\n",
    "        x = tf.cast(x , dtype='float32')\n",
    "        y = tf.cast(y , dtype='float32')\n",
    "\n",
    "        height_float = tf.cast(height, dtype='float32')\n",
    "        width_float = tf.cast(width, dtype='float32')\n",
    "\n",
    "        output_height = output_size[0]\n",
    "        output_width  = output_size[1]\n",
    "\n",
    "        x =x*(width_float)\n",
    "        y =y*(height_float)\n",
    "\n",
    "        x0 = tf.cast(tf.floor(x), 'int32')\n",
    "        x1 = x0 + 1\n",
    "        y0 = tf.cast(tf.floor(y), 'int32')\n",
    "        y1 = y0 + 1\n",
    "\n",
    "        max_y = tf.cast(height - 1, dtype='int32')\n",
    "        max_x = tf.cast(width - 1,  dtype='int32')\n",
    "        \n",
    "        zero = tf.zeros([], dtype='int32')\n",
    "\n",
    "        x0 = tf.clip_by_value(x0, zero, max_x)\n",
    "        x1 = tf.clip_by_value(x1, zero, max_x)\n",
    "        y0 = tf.clip_by_value(y0, zero, max_y)\n",
    "        y1 = tf.clip_by_value(y1, zero, max_y)\n",
    "\n",
    "        flat_image_dimensions = width*height\n",
    "        pixels_batch = tf.range(batch_size)*flat_image_dimensions\n",
    "        flat_output_dimensions = output_height*output_width\n",
    "        base = self._repeat(pixels_batch, flat_output_dimensions)\n",
    "        base_y0 = base + y0*width\n",
    "        base_y1 = base + y1*width\n",
    "        indices_a = base_y0 + x0\n",
    "        indices_b = base_y1 + x0\n",
    "        indices_c = base_y0 + x1\n",
    "        indices_d = base_y1 + x1\n",
    "\n",
    "        flat_image = tf.reshape(image, shape=(-1, num_channels))\n",
    "        flat_image = tf.cast(flat_image, dtype='float32')\n",
    "        pixel_values_a = tf.gather(flat_image, indices_a)\n",
    "        pixel_values_b = tf.gather(flat_image, indices_b)\n",
    "        pixel_values_c = tf.gather(flat_image, indices_c)\n",
    "        pixel_values_d = tf.gather(flat_image, indices_d)\n",
    "        \n",
    "\n",
    "\n",
    "\n",
    "\n",
    "        x0 = tf.cast(x0, 'float32')\n",
    "        x1 = tf.cast(x1, 'float32')\n",
    "        y0 = tf.cast(y0, 'float32')\n",
    "        y1 = tf.cast(y1, 'float32')\n",
    "\n",
    "        area_a = tf.expand_dims(((x1 - x) * (y1 - y)), 1)\n",
    "        area_b = tf.expand_dims(((x1 - x) * (y - y0)), 1)\n",
    "        area_c = tf.expand_dims(((x - x0) * (y1 - y)), 1)\n",
    "        area_d = tf.expand_dims(((x - x0) * (y - y0)), 1)\n",
    "        output = tf.add_n([area_a*pixel_values_a,\n",
    "                           area_b*pixel_values_b,\n",
    "                           area_c*pixel_values_c,\n",
    "                           area_d*pixel_values_d])\n",
    "        return output\n",
    "        \n",
    "    def _repeat(self, x, num_repeats):\n",
    "        ones = tf.ones((1, num_repeats), dtype='int32')\n",
    "        x = tf.reshape(x, shape=(-1,1))\n",
    "        x = tf.matmul(x, ones)\n",
    "        return tf.reshape(x, [-1])\n",
    "    \n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "![](src/loss2.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "##### use conv with fixed weights to compute gradient "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": false,
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "class get_smooth_loss():\n",
    "    def __init__(self,kernel=[[1,2,1],[0,0,0],[-1,-2,-1]],order=1):\n",
    "        self.kernel=np.array(kernel)\n",
    "        self.order=order\n",
    "        \n",
    "        \n",
    "    def build(self,field_c):\n",
    "        v_kernel=self.kernel\n",
    "        h_kernel=self.kernel.T\n",
    "        h_init=keras.initializers.Constant(value=h_kernel)\n",
    "        v_init=keras.initializers.Constant(value=v_kernel)\n",
    "        \n",
    "        self.conv_h=Conv2D(filters=field_c,kernel_size=3,strides=1,kernel_initializer=h_init,padding='same')\n",
    "        self.conv_h.trainable=False\n",
    "        self.conv_v=Conv2D(filters=field_c,kernel_size=3,strides=1,kernel_initializer=v_init,padding='same')\n",
    "        self.conv_v.trainable=False\n",
    "        \n",
    "        \n",
    "    def compute_gradient(self,field):\n",
    "        loss_v=self.conv_v(field)\n",
    "        loss_h=self.conv_h(field)\n",
    "        \n",
    "        gradient_loss=loss_h+loss_v\n",
    "        \n",
    "        return gradient_loss\n",
    "        \n",
    "        \n",
    "    def compute_loss(self,field):\n",
    "        f1_gradient_loss=self.compute_gradient(field)\n",
    "        \n",
    "\n",
    "        \n",
    "        if self.order==1:\n",
    "            loss=tf.reduce_mean(tf.abs(f1_gradient_loss),-1)\n",
    "            loss=tf.reduce_mean(loss)\n",
    "            \n",
    "        if self.order==2:\n",
    "            f2_gradient_loss=self.compute_gradient(f1_gradient_loss)\n",
    "            \n",
    "            loss=tf.reduce_mean(tf.abs(f2_gradient_loss),-1)\n",
    "            loss=tf.reduce_mean(loss)\n",
    "\n",
    "            \n",
    "        return loss\n",
    "\n",
    "        \n",
    "        \n",
    "        \n",
    "\n",
    "    \n",
    "    def __call__(self,field,loss_type=None,reuse=False):\n",
    "        with tf.variable_scope(loss_type,reuse=reuse):\n",
    "            \n",
    "\n",
    "            if loss_type=='flow':\n",
    "                field=Permute((2,1))(field)\n",
    "                field=tf.reshape(field,(-1,128,384,2))\n",
    "                field_c=field.shape.as_list()[1]\n",
    "    # #         if loss_type=='depth':\n",
    "    # #             field=field#tf.reshape(field,(-1,128,384))\n",
    "    # #             field_c=1\n",
    "    #         else:\n",
    "\n",
    "            field_c=field.shape.as_list()[-1]\n",
    "\n",
    "            self.build(field_c)\n",
    "            loss=self.compute_loss(field)\n",
    "            return loss\n",
    "        \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### maybe same as the first loss\n",
    "![](src/loss3.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": false,
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "class get_fb_depth_loss():\n",
    "    def __init__(self):\n",
    "        self.output_size=[128,384]\n",
    "    def __call__(self,depth0,depth1,pos_2d_new,motion,reuse=False):\n",
    "        with tf.variable_scope('fb_depth_loss',reuse=reuse):\n",
    "            batch_size = tf.shape(depth0)[0]\n",
    "            height = tf.shape(depth0)[1]\n",
    "            width = tf.shape(depth0)[2]\n",
    "            num_channels = tf.shape(depth0)[3]\n",
    "            output_height=self.output_size[0]\n",
    "            output_width=self.output_size[1]\n",
    "\n",
    "\n",
    "\n",
    "            x_s = tf.slice(pos_2d_new, [0, 0, 0], [-1, 1, -1],name='err')\n",
    "            y_s = tf.slice(pos_2d_new, [0, 1, 0], [-1, 1, -1])\n",
    "            x_s_flatten = tf.reshape(x_s, [-1])\n",
    "            y_s_flatten = tf.reshape(y_s, [-1])\n",
    "\n",
    "            transformed_depth1 = self._interpolate(depth1,\n",
    "                                                    x_s_flatten,\n",
    "                                                    y_s_flatten,\n",
    "                                                    self.output_size)\n",
    "\n",
    "            transformed_depth1 = tf.reshape(transformed_depth1, shape=(-1,\n",
    "                                                                    output_height,\n",
    "                                                                    output_width,\n",
    "                                                                     num_channels))\n",
    "\n",
    "            motion_z=tf.slice(motion,[0,2,0],[-1,1,-1])\n",
    "            motion_z=tf.reshape(motion_z,(-1,output_height,output_width,1))\n",
    "            transformed_depth0=tf.add(depth0,motion_z)\n",
    "            loss=self.compute_loss( transformed_depth0,transformed_depth1 )\n",
    "        return loss\n",
    "    \n",
    "    \n",
    "    def compute_loss(self,transformed_depth0,transformed_depth1):\n",
    "        \n",
    "        loss=tf.reduce_mean(tf.abs(tf.subtract( transformed_depth0,transformed_depth1)))\n",
    "        return loss\n",
    "        \n",
    "        \n",
    "        \n",
    "        \n",
    "    def _interpolate(self, image, x, y, output_size):\n",
    "        batch_size = tf.shape(image)[0]\n",
    "        height = tf.shape(image)[1]\n",
    "        width = tf.shape(image)[2]\n",
    "        num_channels = tf.shape(image)[3]\n",
    "\n",
    "        x = tf.cast(x , dtype='float32')\n",
    "        y = tf.cast(y , dtype='float32')\n",
    "\n",
    "        height_float = tf.cast(height, dtype='float32')\n",
    "        width_float = tf.cast(width, dtype='float32')\n",
    "\n",
    "        output_height = output_size[0]\n",
    "        output_width  = output_size[1]\n",
    "\n",
    "        x =x*(width_float)\n",
    "        y = y*(height_float)\n",
    "\n",
    "        x0 = tf.cast(tf.floor(x), 'int32')\n",
    "        x1 = x0 + 1\n",
    "        y0 = tf.cast(tf.floor(y), 'int32')\n",
    "        y1 = y0 + 1\n",
    "\n",
    "        max_y = tf.cast(height - 1, dtype='int32')\n",
    "        max_x = tf.cast(width - 1,  dtype='int32')\n",
    "        zero = tf.zeros([], dtype='int32')\n",
    "\n",
    "        x0 = tf.clip_by_value(x0, zero, max_x)\n",
    "        x1 = tf.clip_by_value(x1, zero, max_x)\n",
    "        y0 = tf.clip_by_value(y0, zero, max_y)\n",
    "        y1 = tf.clip_by_value(y1, zero, max_y)\n",
    "\n",
    "        flat_image_dimensions = width*height\n",
    "        pixels_batch = tf.range(batch_size)*flat_image_dimensions\n",
    "        flat_output_dimensions = output_height*output_width\n",
    "        base = self._repeat(pixels_batch, flat_output_dimensions)\n",
    "        base_y0 = base + y0*width\n",
    "        base_y1 = base + y1*width\n",
    "        indices_a = base_y0 + x0\n",
    "        indices_b = base_y1 + x0\n",
    "        indices_c = base_y0 + x1\n",
    "        indices_d = base_y1 + x1\n",
    "\n",
    "        flat_image = tf.reshape(image, shape=(-1, num_channels))\n",
    "        flat_image = tf.cast(flat_image, dtype='float32')\n",
    "        pixel_values_a = tf.gather(flat_image, indices_a)\n",
    "        pixel_values_b = tf.gather(flat_image, indices_b)\n",
    "        pixel_values_c = tf.gather(flat_image, indices_c)\n",
    "        pixel_values_d = tf.gather(flat_image, indices_d)\n",
    "\n",
    "        x0 = tf.cast(x0, 'float32')\n",
    "        x1 = tf.cast(x1, 'float32')\n",
    "        y0 = tf.cast(y0, 'float32')\n",
    "        y1 = tf.cast(y1, 'float32')\n",
    "\n",
    "        area_a = tf.expand_dims(((x1 - x) * (y1 - y)), 1)\n",
    "        area_b = tf.expand_dims(((x1 - x) * (y - y0)), 1)\n",
    "        area_c = tf.expand_dims(((x - x0) * (y1 - y)), 1)\n",
    "        area_d = tf.expand_dims(((x - x0) * (y - y0)), 1)\n",
    "        output = tf.add_n([area_a*pixel_values_a,\n",
    "                           area_b*pixel_values_b,\n",
    "                           area_c*pixel_values_c,\n",
    "                           area_d*pixel_values_d])\n",
    "        return output\n",
    "        \n",
    "    def _repeat(self, x, num_repeats):\n",
    "        ones = tf.ones((1, num_repeats), dtype='int32')\n",
    "        x = tf.reshape(x, shape=(-1,1))\n",
    "        x = tf.matmul(x, ones)\n",
    "        return tf.reshape(x, [-1])\n",
    "    \n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "##  train model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "f_point_cloud_1,f_depth_output=structure_net(I_t0)\n",
    "b_point_cloud_1,b_depth_output=structure_net(I_t1,reuse=True)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "f_pix_pos,f_flow,f_point_cloud_2,f_motion_map=motion_net(I_t0,I_t1,f_point_cloud_1)\n",
    "b_pix_pos,b_flow,b_point_cloud_2,b_motion_map=motion_net(I_t1,I_t0,b_point_cloud_1,reuse=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "f_frame_loss=get_frame_loss()(I_t0,I_t1,f_pix_pos)\n",
    "b_frame_loss=get_frame_loss()(I_t1,I_t0,b_pix_pos,reuse=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "f_flow_sm_loss=get_smooth_loss(order=1)(f_flow,'flow')\n",
    "b_flow_sm_loss=get_smooth_loss(order=1)(b_flow,'flow',reuse=True)\n",
    "\n",
    "f_depth_sm_loss=get_smooth_loss(order=1)(f_depth_output,'depth')\n",
    "\n",
    "b_depth_sm_loss=get_smooth_loss(order=1)(b_depth_output,'depth',reuse=True)\n",
    "\n",
    "f_motion_sm_loss=get_smooth_loss(order=1)(f_motion_map,'motion')\n",
    "\n",
    "b_motion_sm_loss=get_smooth_loss(order=1)(b_motion_map,'motion',reuse=True)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "f_depth_loss=get_fb_depth_loss()(f_depth_output,b_depth_output,f_pix_pos,f_point_cloud_1)\n",
    "b_depth_loss=get_fb_depth_loss()(b_depth_output,f_depth_output,b_pix_pos,b_point_cloud_1,reuse=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/root/anaconda3/lib/python3.6/site-packages/tensorflow/python/ops/gradients_impl.py:91: UserWarning: Converting sparse IndexedSlices to a dense Tensor of unknown shape. This may consume a large amount of memory.\n",
      "  \"Converting sparse IndexedSlices to a dense Tensor of unknown shape. \"\n"
     ]
    }
   ],
   "source": [
    "toal_loss=f_depth_loss+f_depth_sm_loss+f_motion_sm_loss+f_flow_sm_loss+f_frame_loss+\\\n",
    "   b_depth_loss+b_depth_sm_loss+b_motion_sm_loss+b_flow_sm_loss+b_frame_loss\n",
    "train_op=tf.train.AdamOptimizer(learning_rate=0.0003,beta1=0.9).minimize(toal_loss)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "tf.summary.scalar('toal_loss',toal_loss)\n",
    "tf.summary.image('b_depth_output',b_depth_output,1)\n",
    "tf.summary.image('f_depth_output',f_depth_output,1)\n",
    "\n",
    "meger_summary=tf.summary.merge_all()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "!rm -r /tmp/sfm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "!mkdir checkpoint"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "write=tf.summary.FileWriter('/tmp/sfm')\n",
    "write.add_graph(sess.graph)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "load model\n",
      "15.3817\n",
      "109.64\n",
      "57.9887\n",
      "17.5192\n",
      "14.093\n",
      "13.3739\n",
      "12.8767\n",
      "12.8623\n",
      "12.477\n",
      "12.9701\n",
      "12.5193\n",
      "12.2696\n",
      "12.0945\n",
      "11.8624\n",
      "11.8663\n",
      "11.9404\n",
      "11.7443\n",
      "11.8982\n",
      "11.7655\n",
      "12.0749\n",
      "11.6131\n",
      "11.9734\n",
      "11.9707\n",
      "11.5679\n",
      "11.6804\n",
      "11.571\n",
      "11.5112\n",
      "11.3576\n",
      "11.3435\n",
      "11.8275\n",
      "11.4573\n",
      "11.3789\n",
      "11.5034\n",
      "11.428\n",
      "11.1995\n",
      "11.4024\n",
      "11.2043\n",
      "11.4465\n",
      "11.4268\n",
      "11.6385\n",
      "11.17\n",
      "11.0543\n",
      "20.0159\n",
      "13.5467\n",
      "12.1896\n",
      "11.4592\n",
      "11.6704\n",
      "11.201\n",
      "11.2243\n",
      "11.3317\n",
      "11.1422\n",
      "10.7148\n",
      "11.0731\n",
      "11.3487\n",
      "10.6563\n",
      "10.7048\n",
      "10.6398\n",
      "10.6242\n",
      "10.5521\n",
      "10.6531\n",
      "10.8216\n",
      "10.704\n",
      "10.5219\n",
      "10.5184\n",
      "10.4145\n",
      "10.5607\n",
      "10.7068\n",
      "10.6614\n",
      "10.4791\n"
     ]
    },
    {
     "ename": "KeyboardInterrupt",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-42-310b114e0b69>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      9\u001b[0m     \u001b[0mfeed_dict\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m{\u001b[0m\u001b[0mI_t0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0mtest_frame0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mI_t1\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mtest_frame1\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     10\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 11\u001b[0;31m     \u001b[0m_\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msess\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mtrain_op\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mfeed_dict\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mfeed_dict\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     12\u001b[0m \u001b[0;31m#\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     13\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/root/anaconda3/lib/python3.6/site-packages/tensorflow/python/client/session.py\u001b[0m in \u001b[0;36mrun\u001b[0;34m(self, fetches, feed_dict, options, run_metadata)\u001b[0m\n\u001b[1;32m    765\u001b[0m     \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    766\u001b[0m       result = self._run(None, fetches, feed_dict, options_ptr,\n\u001b[0;32m--> 767\u001b[0;31m                          run_metadata_ptr)\n\u001b[0m\u001b[1;32m    768\u001b[0m       \u001b[0;32mif\u001b[0m \u001b[0mrun_metadata\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    769\u001b[0m         \u001b[0mproto_data\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtf_session\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mTF_GetBuffer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrun_metadata_ptr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/root/anaconda3/lib/python3.6/site-packages/tensorflow/python/client/session.py\u001b[0m in \u001b[0;36m_run\u001b[0;34m(self, handle, fetches, feed_dict, options, run_metadata)\u001b[0m\n\u001b[1;32m    963\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0mfinal_fetches\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0mfinal_targets\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    964\u001b[0m       results = self._do_run(handle, final_targets, final_fetches,\n\u001b[0;32m--> 965\u001b[0;31m                              feed_dict_string, options, run_metadata)\n\u001b[0m\u001b[1;32m    966\u001b[0m     \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    967\u001b[0m       \u001b[0mresults\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/root/anaconda3/lib/python3.6/site-packages/tensorflow/python/client/session.py\u001b[0m in \u001b[0;36m_do_run\u001b[0;34m(self, handle, target_list, fetch_list, feed_dict, options, run_metadata)\u001b[0m\n\u001b[1;32m   1013\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0mhandle\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1014\u001b[0m       return self._do_call(_run_fn, self._session, feed_dict, fetch_list,\n\u001b[0;32m-> 1015\u001b[0;31m                            target_list, options, run_metadata)\n\u001b[0m\u001b[1;32m   1016\u001b[0m     \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1017\u001b[0m       return self._do_call(_prun_fn, self._session, handle, feed_dict,\n",
      "\u001b[0;32m/root/anaconda3/lib/python3.6/site-packages/tensorflow/python/client/session.py\u001b[0m in \u001b[0;36m_do_call\u001b[0;34m(self, fn, *args)\u001b[0m\n\u001b[1;32m   1020\u001b[0m   \u001b[0;32mdef\u001b[0m \u001b[0m_do_call\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1021\u001b[0m     \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1022\u001b[0;31m       \u001b[0;32mreturn\u001b[0m \u001b[0mfn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   1023\u001b[0m     \u001b[0;32mexcept\u001b[0m \u001b[0merrors\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mOpError\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1024\u001b[0m       \u001b[0mmessage\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcompat\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mas_text\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0me\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmessage\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/root/anaconda3/lib/python3.6/site-packages/tensorflow/python/client/session.py\u001b[0m in \u001b[0;36m_run_fn\u001b[0;34m(session, feed_dict, fetch_list, target_list, options, run_metadata)\u001b[0m\n\u001b[1;32m   1002\u001b[0m         return tf_session.TF_Run(session, options,\n\u001b[1;32m   1003\u001b[0m                                  \u001b[0mfeed_dict\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfetch_list\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtarget_list\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1004\u001b[0;31m                                  status, run_metadata)\n\u001b[0m\u001b[1;32m   1005\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1006\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0m_prun_fn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msession\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mhandle\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfeed_dict\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfetch_list\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mKeyboardInterrupt\u001b[0m: "
     ]
    }
   ],
   "source": [
    "sess.run(tf.global_variables_initializer())\n",
    "saver=tf.train.Saver()\n",
    "for step in range(10000):\n",
    "    ckpt = tf.train.get_checkpoint_state('./checkpoint/')\n",
    "    if (step==0) and ckpt and ckpt.model_checkpoint_path:\n",
    "        print('load model')\n",
    "        saver.restore(sess, ckpt.model_checkpoint_path)\n",
    "\n",
    "    feed_dict={I_t0:test_frame0,I_t1: test_frame1}\n",
    "    \n",
    "    _=sess.run([train_op],feed_dict=feed_dict)\n",
    "#     \n",
    "\n",
    "    if step%20==0:\n",
    "        train_loss=sess.run(toal_loss,feed_dict=feed_dict)\n",
    "        print(train_loss)\n",
    "        \n",
    "    if step%100==0:\n",
    "        s=sess.run(meger_summary,feed_dict=feed_dict )\n",
    "        write.add_summary(s,step)\n",
    "        saver.save(sess, './checkpoint/'+'my-model', global_step=step)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
